#pragma once

#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "SimulationSpace.h"

using namespace System::Windows::Forms;

namespace OpenGLForm 
{
	/*
* @Mateusz Janczewski
*/
	public ref class COpenGL: public System::Windows::Forms::NativeWindow
	{
	public:

		SimulationSpace*			space;
		
		COpenGL(System::Windows::Forms::Panel ^ parentForm,  GLsizei iWidth, GLsizei iHeight)
		{
			
			this->space = new SimulationSpace();
			CreateParams^ cp = gcnew CreateParams;

			// Set the position on the form
			cp->X = 0;
			cp->Y = 0;
			cp->Height = iHeight;
			cp->Width = iWidth;

			// Specify the form as the parent.
			cp->Parent = parentForm->Handle;

			// Create as a child of the specified parent and make OpenGL compliant (no clipping)
			cp->Style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

			// Create the actual window
			this->CreateHandle(cp);

			m_hDC = GetDC((HWND)this->Handle.ToPointer());

			m_hDC = GetDC((HWND)this->Handle.ToPointer());
			if(m_hDC)
			{
			wglMakeCurrent(m_hDC, NULL); 
			MySetPixelFormat(m_hDC);
			ReSizeGLScene(iWidth, iHeight);
			InitGL();
			}


			rtri = 0.0f;
			rquad = 0.0f;
		}

		
		System::Void Update(int milis)
			   {
				   float delta = space->simulationScale * milis;
				   delta /= 1000000;
				   space->Update(delta);
				   space->simulationTime += delta;
			   }
		System::Void Render(System::Void)
		{
			
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear screen and depth buffer
			glLoadIdentity();									// Reset the current modelview matrix
			glTranslatef(0.0f,-5.0f,-10.0f);					// Move left 1.5 units and into the screen 6.0
			space->Draw();
		}

		System::Void SwapOpenGLBuffers(System::Void)
		{
			SwapBuffers(m_hDC) ;
		}

	private:
		HDC m_hDC;
		HGLRC m_hglrc;
		GLfloat	rtri;				// Angle for the triangle
		GLfloat	rquad;				// Angle for the quad
		

	protected:
		~COpenGL(System::Void)
		{
			this->DestroyHandle();
		}

		GLint MySetPixelFormat(HDC hdc)
		{
			static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
				{
					sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
					1,											// Version Number
					PFD_DRAW_TO_WINDOW |						// Format Must Support Window
					PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
					PFD_DOUBLEBUFFER,							// Must Support Double Buffering
					PFD_TYPE_RGBA,								// Request An RGBA Format
					16,										// Select Our Color Depth
					0, 0, 0, 0, 0, 0,							// Color Bits Ignored
					0,											// No Alpha Buffer
					0,											// Shift Bit Ignored
					0,											// No Accumulation Buffer
					0, 0, 0, 0,									// Accumulation Bits Ignored
					16,											// 16Bit Z-Buffer (Depth Buffer)  
					0,											// No Stencil Buffer
					0,											// No Auxiliary Buffer
					PFD_MAIN_PLANE,								// Main Drawing Layer
					0,											// Reserved
					0, 0, 0										// Layer Masks Ignored
				};
			
			GLint  iPixelFormat; 
		 
			// get the device context's best, available pixel format match 
			if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
			{
				MessageBox::Show("ChoosePixelFormat Failed");
				return 0;
			}
			 
			// make that match the device context's current pixel format 
			if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
			{
				MessageBox::Show("SetPixelFormat Failed");
				return 0;
			}

			if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
			{
				MessageBox::Show("wglCreateContext Failed");
				return 0;
			}

			if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
			{
				MessageBox::Show("wglMakeCurrent Failed");
				return 0;
			}


			return 1;
		}

		bool InitGL(GLvoid)										// All setup for opengl goes here
		{

			glShadeModel(GL_SMOOTH);
			glClearColor(0.2f, 0.2f, 0.4f, 0.5f);				
			glClearDepth(1.0f);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_LEQUAL);
			glEnable(GL_COLOR_MATERIAL);
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	
			glEnable(GL_LIGHTING);
			glEnable(GL_LIGHT0);
			GLfloat lightPos[4] = {-1.0,1.0,0.5,0.0};
			glLightfv(GL_LIGHT0,GL_POSITION,(GLfloat *) &lightPos);

			glEnable(GL_LIGHT1);

			GLfloat lightAmbient1[4] = {0.0,0.0,0.0,0.0};
			GLfloat lightPos1[4] = {1.0,0.0,-0.2,0.0};
			GLfloat lightDiffuse1[4] = {0.5,0.5,0.3,0.0};

			glLightfv(GL_LIGHT1,GL_POSITION,(GLfloat *) &lightPos1);
			glLightfv(GL_LIGHT1,GL_AMBIENT,(GLfloat *) &lightAmbient1);
			glLightfv(GL_LIGHT1,GL_DIFFUSE,(GLfloat *) &lightDiffuse1);

			glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);

			return TRUE;										// Initialisation went ok
		}

		GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize and initialise the gl window
		{
			glViewport(0, 0, width, height);
			glMatrixMode(GL_PROJECTION); 
			glLoadIdentity();  
			if (height==0)  
				gluPerspective(80,(float)width,1.0,5000.0);
			else
				gluPerspective (80,( float )width /( float )height,1.0,5000.0 );
			glMatrixMode(GL_MODELVIEW);  
			glLoadIdentity(); 									// Reset The Modelview Matrix
		}
	};
}